/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.lang.reflect;

/**
 * {@code Array} 类提供静态方法来动态创建和访问 Java 数组。
 *
 * <p>{@code Array} 允许在 get 或 set 操作期间进行扩展转换，
 * 但如果发生收缩转换则抛出 {@code IllegalArgumentException}。
 *
 * @author Nakul Saraiya
 */
public final
class Array {

    /**
     * 构造器。Array 类不可实例化。
     */
    private Array() {}

    /**
     * 创建具有指定组件类型和长度的新数组。
     * 调用此方法等价于按如下方式创建数组：
     * <blockquote>
     * <pre>
     * int[] x = {length};
     * Array.newInstance(componentType, x);
     * </pre>
     * </blockquote>
     *
     * <p>新数组的维数不得超过 255。
     *
     * @param componentType 表示新数组组件类型的 {@code Class} 对象
     * @param length 新数组的长度
     * @return 新数组
     * @exception NullPointerException 如果指定的 {@code componentType} 参数为 null
     * @exception IllegalArgumentException 如果 componentType 是 {@link
     * Void#TYPE} 或者请求的数组实例的维数超过 255
     * @exception NegativeArraySizeException 如果指定的 {@code length} 为负数
     */
    public static Object newInstance(Class<?> componentType, int length)
        throws NegativeArraySizeException {
        return newArray(componentType, length);
    }

    /**
     * 创建具有指定组件类型和维度的新数组。
     * 如果 {@code componentType} 表示非数组类或接口，
     * 则新数组具有 {@code dimensions.length} 个维度，
     * 并以 {@code componentType} 作为其组件类型。
     * 如果 {@code componentType} 表示数组类，
     * 则新数组的维数等于 {@code dimensions.length} 与
     * {@code componentType} 的维数之和。
     * 在这种情况下，新数组的组件类型是 {@code componentType} 的组件类型。
     *
     * <p>新数组的维数不得超过 255。
     *
     * @param componentType 表示新数组组件类型的 {@code Class} 对象
     * @param dimensions 表示新数组各维度的 {@code int} 数组
     * @return 新数组
     * @exception NullPointerException 如果指定的 {@code componentType} 参数为 null
     * @exception IllegalArgumentException 如果指定的 {@code dimensions}
     * 参数是零维数组，或者 componentType 是 {@link Void#TYPE}，
     * 或者请求的数组实例的维数超过 255
     * @exception NegativeArraySizeException 如果指定的 {@code dimensions}
     * 参数中的任何组件为负数
     */
    public static Object newInstance(Class<?> componentType, int... dimensions)
        throws IllegalArgumentException, NegativeArraySizeException {
        return multiNewArray(componentType, dimensions);
    }

    /**
     * 返回指定数组对象的长度，以 {@code int} 形式返回。
     *
     * @param array 数组
     * @return 数组的长度
     * @exception IllegalArgumentException 如果对象参数不是数组
     */
    public static native int getLength(Object array)
        throws IllegalArgumentException;

    /**
     * 返回指定数组对象中索引组件的值。
     * 如果值是基本类型，则自动包装为对象。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值（可能已包装）
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     */
    public static native Object get(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code boolean} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native boolean getBoolean(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code byte} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native byte getByte(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code char} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native char getChar(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code short} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native short getShort(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code int} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native int getInt(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code long} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native long getLong(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code float} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native float getFloat(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 返回指定数组对象中索引组件的值，以 {@code double} 形式返回。
     *
     * @param array 数组
     * @param index 索引
     * @return 指定数组中索引组件的值
     * @exception NullPointerException 如果指定的对象为 null
     * @exception IllegalArgumentException 如果指定的对象不是数组，
     * 或者索引元素无法通过恒等或扩展转换转换为返回类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#get
     */
    public static native double getDouble(Object array, int index)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的新值。
     * 如果数组具有基本组件类型，则新值首先自动拆箱。
     * @param array 数组
     * @param index 数组中的索引
     * @param value 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者数组组件类型是基本类型且拆箱转换失败
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     */
    public static native void set(Object array, int index, Object value)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code boolean} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param z 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setBoolean(Object array, int index, boolean z)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code byte} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param b 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setByte(Object array, int index, byte b)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code char} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param c 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setChar(Object array, int index, char c)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code short} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param s 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setShort(Object array, int index, short s)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code int} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param i 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setInt(Object array, int index, int i)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code long} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param l 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setLong(Object array, int index, long l)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code float} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param f 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setFloat(Object array, int index, float f)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /**
     * 将指定数组对象的索引组件的值设置为指定的 {@code double} 值。
     * @param array 数组
     * @param index 数组中的索引
     * @param d 索引组件的新值
     * @exception NullPointerException 如果指定的对象参数为 null
     * @exception IllegalArgumentException 如果指定的对象参数不是数组，
     * 或者指定的值无法通过恒等或基本类型扩展转换转换为底层数组的组件类型
     * @exception ArrayIndexOutOfBoundsException 如果指定的 {@code index}
     * 参数为负数，或者大于等于指定数组的长度
     * @see Array#set
     */
    public static native void setDouble(Object array, int index, double d)
        throws IllegalArgumentException, ArrayIndexOutOfBoundsException;

    /*
     * Private
     */

    private static native Object newArray(Class<?> componentType, int length)
        throws NegativeArraySizeException;

    private static native Object multiNewArray(Class<?> componentType,
        int[] dimensions)
        throws IllegalArgumentException, NegativeArraySizeException;


}
